/**
 *
 * @author Eric Jahn Course: Object Oriented Programming Final Project
 *
 * Due Date: August 3, 2012
 */
package oop.chat.connection;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import oop.chat.data.ConnectionStatus;
import oop.chat.data.Message;
import oop.chat.gui.Gui;
import oop.chat.user.UserAccount;

/**
 * clientside of the chat
 * @author Eric Jahn
 */
public class Client 
{
    public static final String SEPARATOR = ":";
    //connection variables 	
    private String host;
    private int port;
    private Socket client;
    private ConnectionStatus connectionStatus;
    private ObjectOutputStream outputStream;
    private ObjectInputStream inputStream;
	
	//gui instance
	private Gui gui;

    //user account 	
    private UserAccount user;

	/**
	 * initializes the client without gui instance
	 * @param	host			String
	 * @param	port			Integer
	 * @param	userAccount		UserAccount
	 */
    public Client(String host, int port, UserAccount userAccount)
    {
        //initialize variables 		
        this.host = host;
        this.port = port;
        this.user = userAccount;
        this.connectionStatus = ConnectionStatus.DISCONNECTED;
		this.gui = null;
    }
	
	public void setGui(Gui gui)
	{
		this.gui = gui;
	}

    /**
     * set a user account
     *
     * @param	user	UserAccount
     */
    public void setUserAccount(UserAccount user)
    {
        this.user = user;
    }

    /**
     * gets the user account
     *
     * @return	user	UserAccount
     */
    public final UserAccount getUserAccount()
    {
        return this.user;
    }

	/**
	 * start running
	 * @return	ConnectionStatus 
	 */
    public ConnectionStatus start()
    {
        return this.establishConnection();
    }

	/**
	 * tries to establish a new connection to the server
	 * @return	ConnectionStatus
	 */
    public ConnectionStatus establishConnection()
    {
        try
        {
            this.client = new Socket(this.host, this.port);
            this.outputStream = new ObjectOutputStream(this.client.getOutputStream());
            this.inputStream = new ObjectInputStream(this.client.getInputStream());
            // creates the Thread to listen from the server 
            new ListenFromServer().start();
            this.connectionStatus = ConnectionStatus.CONNECTED;

            /**
             * send login, needed to prevent server from hanging on client start
             */
            Request request = new Request(RequestType.LOGIN, user, null);
            this.outputStream.writeObject(request);
            this.outputStream.reset();
        }
        catch(IOException ex)
        {
            this.connectionStatus = ConnectionStatus.CONNECTION_ERROR;
            System.out.println("Error connecting to server: " + ex.toString());
        }
        return this.connectionStatus;
    }

    public void closeConnection()
    {
        try
        {
            this.inputStream.close();
            this.outputStream.close();
            this.client.close();
        }
        catch (IOException ex)
        {
            System.out.println("Error closing connection to server: "
                    + ex.toString());
        }
		
        this.connectionStatus = ConnectionStatus.DISCONNECTED;
    }

    public void processMessage(String input)
    {
        String[] msgParts = input.split(SEPARATOR, 2);
        String command = msgParts[0];
        String text = null;
        if (msgParts.length >= 2)
        {
            text = msgParts[1];
        }
        // TODO errorhandling for one word/no param commands
        RequestType requestType = RequestType.valueOf(command.toUpperCase());
        Request request = requestType.prepareRequest(user, text);
        
        if (connectionStatus == ConnectionStatus.CONNECTED)
        {
            try
            {
                this.outputStream.writeObject(request);
                this.outputStream.reset();
            }
            catch (IOException ex)
            {
                System.out.println("Error sending message: " + ex.toString());
            }
        }
    }
    /*
     * a class that waits for the message from the server and append them to the
     * JTextArea if we have a GUI or simply System.out.println() it in console
     * mode
     */
    class ListenFromServer extends Thread
    {
        @Override
        public void run()
        {
            while (true)
            {
				Object input = null;
				if(connectionStatus == ConnectionStatus.CONNECTED)
				{
					try
					{
						input = inputStream.readObject();
						if(input instanceof Message)
						{
							//the client has received a new message, display it
							Message message = (Message)input;
							if(gui == null)
							{
								//display message in console
								System.out.println(message.toString());
							}
							else
							{
								//display message in gui window
								gui.displayNewMessage(message);
							}
						}
						else
						{
							user.setLogin((boolean)input);
						}
					}
					catch (IOException | ClassNotFoundException e)
					{
						e.printStackTrace();
					}
				}
            }
        }
    }
}